con

  '_xinfreq = 5_000_000
  _clkfreq = 80_000_000
  _clkmode = xtal1 + pll16x


  TX_PIN        = 30
  BAUDRATE      = 115_200

pub Standalone_Tester

  'launch main tester into each cog
' cntStart := cnt + clkfreq*2
  coginit(7,@entry,@OtherTests)
  coginit(6,@entry,@OtherTests)
  coginit(5,@entry,@OtherTests)
  coginit(4,@entry,@OtherTests)
  coginit(3,@entry,@OtherTests)
  coginit(2,@entry,@OtherTests)
  coginit(1,@entry,@OtherTests)
  coginit(0,@entry,@OtherTests)

dat

                        org     0

entry              





OtherTests            

TestCogRAM              waitcnt cntStart, #0            'Sync cogs; all cogs wait for same moment in time

'
'
' Execute many alu instructions and compare results to other cogs
'
test_alu                test    lfsr0,taps0     wc      'step lfsr's
                        rcl     lfsr0,#1
                        test    lfsr1,taps1     wc
                        rcl     lfsr1,#1
                        test    lfsr2,taps2     wc
                        rcl     lfsr2,#1

                        mov     :alu,lfsr0              'prepare alu instruction
                        cmp     :alu,alu_min    wc      '(limit to valid range)
        if_c            add     :alu,alu_min
                        cmp     :alu,alu_max    wc
        if_nc           add     :alu,alu_max
                        cmp     :alu,alu_jmp    wc      '(convert jmpret to xor)
        if_nc           cmp     alu_and,:alu    wc
        if_nc           add     :alu,alu_min

                        test    :alu,alu_i      wc      'prepare source
        if_nc           movs    :alu,#lfsr1

                        mov     alu_d,lfsr2             'prepare destination
                        movd    :alu,#alu_d

                        test    lfsr0,alu_c     wc      'prepare flags
                        test    lfsr0,alu_z     wz

:alu                    nop                             'execute alu instruction

                        negc    alu_f,#1                'save result flags
                        muxz    alu_f,#2

                        cogid   t1                      'write results to main memory
                        shl     t1,#3
                        wrlong  alu_d,t1
                        add     t1,#4
                        wrlong  alu_f,t1

                        mov     t1,#0                   'compare results to other cogs
:cmp                    rdlong  t2,t1                   '(check destination)
                        add     t1,#4
                        cmp     t2,alu_d        wz
        if_nz           jmp     #Do_test_fail
                        rdlong  t2,t1                   '(check flags)
                        add     t1,#4
                        cmp     t2,alu_f        wz
        if_nz           jmp     #Do_test_fail
                        cmp     t1,#8<<3        wz
        if_nz           jmp     #:cmp

                        djnz    alu_tests,#test_alu     'loop until tests done

                        
                        jmp     #Do_test_pass




alu_tests               long    100_000
alu_min                 long    $1000_0000
alu_max                 long    $E400_0000
alu_jmp                 long    $5C00_0000
alu_and                 long    $6000_0000
alu_i                   long    $0040_0000
alu_c                   long    $0000_0200
alu_z                   long    $0000_0400

lfsr0                   long    $12345678               'lfsr starts
lfsr1                   long    $F0459BED
lfsr2                   long    $7E004A32

taps0                   long    $802A5000               'lfsr taps
taps1                   long    $80524800
taps2                   long    $81060280



{

'
' Pass/Error
'
pass                    cogid   t1
                        mov     status_code,#1
                        shl     status_code,t1

error                   cogid   t1
                        shl     status_pin,t1

                        mov     dira,status_pin
                        mov     t1,cnt
                        add     t1,status_delay

:loop                   waitcnt t1,status_delay
                        test    status_code,#$80  wc
                        muxc    outa,status_pin
                        rcl     status_code,#1
                        jmp     #:loop                               
                        
}



status_code             long    $FF
status_pin              long    $01000000
status_delay            long    80_000_000 / 100        '10ms @ 80MHz



'================================ Do Test Fail ==================================================================
'       This routine is called when the value read back from Hub RAM differs from what was just written.  This
'       indicates a memory failure.

Do_test_fail

              cogid cog_num 'Save the cog ID

              mov       t0,cog_num              'Copy the cog ID to be able to work with it
              add       t0,#1                   'Increment the value to avoid no time delay being added
              mov       timer,#0                'Zero out the timer variable

              mov       t1,one_sec              'one second...
              shr       t1,#3                   '...divided by 8 (to overlap execution a bit)
                            
:loop         add       timer,t1                'simple multiplication
              djnz      t0,#:loop

              
              add       timer,cnt              
              waitcnt   timer,#0                'do the actual wait
              
              mov       a0,#cog_num_str         'a0 = address of string to print              
              call      #Print_Str              'print the Cog number string
              
              cogid     acc
              add       acc,#$30                'add this constant to make the decimal number an ASCII char
              call      #Serout                 'print the number
              
              mov       a0,#fail_str            'setup the "fail" string
              call      #Print_str              'print the "fail" string
              jmp       #hang                   'the test failed, hang the cog up!


Do_test_pass
              cogid cog_num       'Save the cog ID

              mov       t0,cog_num              'Copy the cog ID to be able to work with it
              add       t0,#1                   'Increment the value to avoid no time delay being added
              mov       timer,#0                'Zero out the timer variable

              mov       t1,one_sec              'one second...
              shr       t1,#3                   '...divided by 8 (to overlap execution a bit)
                            
:loop         add       timer,t1                'simple multiplication
              djnz      t0,#:loop

              
              add       timer,cnt              
              waitcnt   timer,#0                'do the actual wait
              
              mov       a0,#cog_num_str         'a0 = address of string to print              
              call      #Print_Str              'print the Cog number string
              
              cogid     acc
              add       acc,#$30                'add this constant to make the decimal number an ASCII char
              call      #Serout                 'print the number
              
              mov       a0,#pass_str            'setup the "pass" string
              call      #Print_str              'print the "pass" string
              mov       acc,#13
              jmp       #hang                   'the test failed, hang the cog up!

'================================ Hang ==========================================================================
'       Hang the cog's execution.  This routine simply stops the cog.

hang          cogstop  cog_num                  'stop self
              jmp       #hang                   'shouldnt ever have to jump back, but just in case...


'================================ Print String ==================================================================

Print_Str     movd      :strloop,a0
              nop
:strloop      cmp       0-0,#0            wz    'check to see if we have reached our zero-terminator
        

              'xor      outa, #1                'toggle an LED (for debugging)

              movs      :load,a0
              nop
              nop
        if_z  jmp       #Print_Str_ret          'if we have, then jump to the return address
        
:load         mov       acc,0-0                 'load the char into the accumulator for transmission
              call      #Serout                 'send the char
              
              add       a0,#1                   'increment the string address pointer
              movd      :strloop,a0             'set up the next char to be compared
              nop                               'let a few "do-nothing" instructions through to allow the destination
              nop                               'register modificaiton take place.
              jmp       #:strloop               'do it again

Print_Str_ret
              ret

'================================ Serout =======================================================================

Serout        or        outa,out_mask           'set TX_PIN high for serial transmission
              or        dira,out_mask           'Set TX_PIN to output
              mov       bit_cnt,#10             'extra stop bit padding, set up the number of bits to be TXed
              mov       t0,#%1                  'extra stop bit padding
              shl       t0,#8                   'get ready to OR this with the data byte
              or        acc,t0                  'OR it
              shl       acc,#1                  'shift in one start bit

              mov       bit_time,baud           'calc the number of clock ticks for our baud rate
              add       bit_time,cnt            'add to the current system time
              
:bitloop      shr       acc,#1            wc    'put bit to be TXed into carry
              muxc      outa,out_mask           'stick the state of carry to the pin
              waitcnt   bit_time,baud           'wait for the right amount of time
              djnz      bit_cnt,#:bitloop       'do it again until we run out of bits to TX
              
              andn      dira,out_mask           'make the pin an input to let the other cogs have a chance at communicating
Serout_ret    ret


'================================ Variable Definitions =========================================================


one_sec       long      _clkfreq                'number of clock ticks in one second
sync_start    long      0-0                     'written by the spin init code

cntStart                long    0                                               'Cog synch moment; written by high-level

num_longs     long      $8000>>2                'the number of longs in Hub RAM
pattern       long      $5555_5555              'the starting bit pattern used to read/write to Hub RAM

out_mask      long      1<<TX_PIN               'output pin mask

'Simple string definitions.  Each character byte is stored as a long to simplify the transmission code.
cog_num_str   long      "Cog ", 0
pass_str      long      ": PASS", 0
fail_str      long      ": !!!!  FAIL", 0

baud          long      _clkfreq / BAUDRATE     'number of clock ticks to acheive a specified baud rate



'================================ Uninitialized Cog Variable Definitions =======================================

acc           res       1
bit_time      res       1
bit_cnt       res       1
cog_num       res       1
curr_addy     res       1
timer         res       1

'temporaries
t0            res       1
t1            res       1
t2            res       1
t3            res       1

'return registers
r0            res       1
r1            res       1

'argument registers
a0            res       1
a1            res       1


alu_d                   res     1                       'alu test
alu_f                   res     1
